<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
<script>

  const obj = {
    name: {
      msg: [2, 3, 4]
    }
  }

  obj.next = obj
  console.log(deepCopy(obj))
  function deepCopy(data) {
    // 存放一个上层map结构
    const map = new WeakMap()
    function dp(data) {
      // 1、首先判断当前对象是否已经被处理过,
      // 如果被处理过，说明存在循环引用，直接返回上一次处理的结果，不需要重复处理，不然会出现死递归
      const existObj = map.get(data)
      if (existObj) {
        return existObj
      }
      // 2、如果没有被处理过，则声明一个对象/数组 存储新拷贝的数据
      let result = Array.isArray(data) ? [] : {};
      // 3、把当前声明好的预期存储拷贝结果的result，通过原数据映射的方式存储到map结构
      //    ---> 下一次就不会再去处理当前数据
      map.set(data, result)

      // 4、开始处理数据，处理的结果写入到已经声明好的result里面去
      for (const key in data) {
        let item = data[key]
        if (typeof item === 'object') {
          result[key] = dp(item)
        } else {
          result[key] = item
        }
      }
      // 返回处理好的结果
      return result
    }

    return dp(data)
  }
</script>
</body>
</html>
